<?php
ini_set("display_errors", true);
error_reporting(E_ALL);

require_once('simpletest/autorun.php');
require_once('../src/scottlib.php');
require_once('../src/scottlib-orm.php');

/**
 * Unit tests for scottlib core
 * @author Aaron Collegeman aaroncollegeman.com
 * @since 0.1.3
 */

class TestCore extends UnitTestCase {

	private $conn;
	
	private $version;
	
	function setUp() {
		//$this->conn = connect(':/tmp/mysql.sock', 'root', 'password', 'mysql');
		$this->conn = connect('localhost', 'root', '14allall41', 'mysql');
	}
	
	function tearDown() {
		disconnect();
	}
	
	function testNamespaceAvailabilityDetection() {
		// there is no framework and no extra libraries, so all core global functions should be available
		$this->assertTrue(function_exists('db'));
		$this->assertTrue(function_exists('select'));
		$this->assertTrue(function_exists('query'));
		$this->assertTrue(function_exists('insert'));
		$this->assertTrue(function_exists('update'));
		$this->assertTrue(function_exists('delete'));
		$this->assertTrue(function_exists('execute'));
		$this->assertTrue(function_exists('val'));
		$this->assertTrue(function_exists('begin'));
		$this->assertTrue(function_exists('beginTransaction'));
		$this->assertTrue(function_exists('rollback'));
		$this->assertTrue(function_exists('commit'));
	}
	
	function testDbFunction() {
		$this->assertEqual($this->conn, db());	
	}
	
	function testPreparedStatements() {
		// single parameter, no escaping
		$this->assertEqual('SELECT @@VERSION', prepare('SELECT %p', '@@VERSION'));
		
		// single parameter, escaping
		$this->assertEqual("SELECT * FROM `table` WHERE column='value'", prepare('SELECT * FROM `table` WHERE column=?', 'value'));
		
		// both
		$this->assertEqual("SELECT * FROM `table` WHERE column='value'", prepare('SELECT * FROM # WHERE column=?', array('table', 'value')));
		
		// single parameter, no escaping because numeric
		$this->assertEqual("SELECT 3.1415 4 0.0003 'value'", prepare('SELECT ? ? ? ?', array(3.1415, 4, 0.0003, 'value')));
		
		// with new lines and tabs
		$this->assertEqual("
			SELECT *
			FROM `table`
			WHERE
				column = 'value'
		", prepare("
			SELECT *
			FROM #
			WHERE
				column = ?
		", array('table', 'value')));
		
		// named parameters
		$this->assertEqual(
			"SELECT * FROM `table` WHERE `column`='value1' OR `column`='value2'", 
			prepare("SELECT * FROM `table` WHERE `column`=:param1 OR `column`=:param2", array(
				'param1' => 'value1', 
				'param2' => 'value2'
			))
		);
		
		// named parameters with optional (null) replacement
		$this->assertEqual(
			"SELECT * FROM `table` WHERE `column`=null OR `column`='value2'", 
			prepare("SELECT * FROM `table` WHERE `column`=!:param1 OR `column`=:param2", array(
				'param2' => 'value2'
			))
		); 
		
		// named parameters and numeric parameter values
		$this->assertEqual(
			"SELECT * FROM `table` WHERE `column1`=3.1415 AND `column2`=4 AND `column3`=0.0003", 
			prepare("SELECT * FROM `table` WHERE `column1`=:param1 AND `column2`=:param2 AND `column3`=:param3", array(
				'param1' => 3.1415, 
				'param2' => 4, 
				'param3' => 0.0003
			))
		);
		
		// named parameters for system objects
		$this->assertEqual(
			"SELECT * FROM `foo` WHERE `bar`=1 OR `bar`='value'", 
			prepare("SELECT * FROM #table WHERE #column=:param1 OR #column=:param2", array(
				'table' => 'foo', 
				'column' => 'bar', 
				'param1' => 1, 
				'param2' => 'value'
			))
		);
		
		// calendar
		$this->assertEqual(
			"SELECT * FROM table WHERE date='1981/10/26 05:00:00'",
			prepare("SELECT * FROM table WHERE date=%c", '10/26/1981 5am')
		); 
		
		// numeric
		$this->assertEqual(
			"SELECT * FROM table WHERE number=3.1415 OR number=5",
			prepare("SELECT * FROM table WHERE number=%d OR number=%n", array(
				3.1415,
				5
			))
		);
		
		// string
		$this->assertEqual(
			"SELECT * FROM table WHERE value='foo'",
			prepare("SELECT * FROM table WHERE value=%s", 'foo')
		);
		
	}
	
	function testSelectAsPrepare() {
		$record = select("
			SELECT
			? as `int`,
			? as `float`,
			? as `bool`,
			%c as `date`
		", 1, 3.1415, true, "Today")->first();
		
		$this->assertEqual($record->int, 1);
		$this->assertEqual($record->float, 3.1415);
		$this->assertEqual($record->bool, true);
		$this->assertEqual(strtotime($record->date), strtotime('Today'));
		
		$record = select("
			SELECT
			:int as `int`,
			:float as `float`,
			:bool as `bool`,
			:date as `date`
		", array(
		'int' => 1, 
		'float' => 3.1415, 
		'bool' => true, 
		'date' => strtotime("Today")
		))->first();
		
		$this->assertEqual($record->int, 1);
		$this->assertEqual($record->float, 3.1415);
		$this->assertEqual($record->bool, true);
		$this->assertEqual($record->date, strtotime('Today'));
	}
	
	function testBasicQuerying() {
		$this->version = val('SELECT @@VERSION');
		$this->assertTrue(strlen($this->version));
	
		$rs = select('SELECT @@VERSION as `version`');
		$this->assertTrue($rs->count() === 1);
		$this->assertTrue($rs->fieldCount() === 1);
		
		foreach($rs->objects() as $i => $value) {
			$this->assertEqual($this->version, $value->version);
		}
		$this->assertEqual($i, 0);
		$i = null;
		
		foreach($rs->hashes() as $i => $value) {
			$this->assertEqual($this->version, $value['version']);
		}
		$this->assertEqual($i, 0);
		$i = null;
		
		foreach($rs->arrays() as $i => $value) {
			$this->assertEqual($this->version, $value[0]);
		}
		$this->assertEqual($i, 0);
		$i = null;	
	}
	
	function testObjectArrayWrapper() {
		$o0 = new ObjectClass();
		$o0->setName('o0');
		$o0->foo = 'bar';
		$o0->sample = 'sample';
		
		$o1 = new ObjectClass();
		$o1->setName('o1');
		$o1->foo = 'hello, world!';
		$o1->sample = 'sample2';
		
		$wrapped = new slObjectArrayWrapper(array($o0, $o1));
		
		// standard foreach approach
		foreach($wrapped as $i => $object) {
			$this->assertEqual(eval("return \$o$i"."->foo;"), $object->foo);
			$this->assertEqual(eval("return \$o$i"."->sample;"), $object->sample);	
		}
		
		// count
		$this->assertEqual(2, $wrapped->count());
		
		// wrapped property access
		$this->assertEqual($o0->foo, $wrapped->foo);
		$this->assertEqual($o0->sample, $wrapped->sample);
		
		// wrapped method access
		$this->assertEqual($o0->getName(), $wrapped->getName());
	
		$wrapped->setName('12345');
		$this->assertEqual($o0->getName(), $wrapped->getName());
	}
	
	
}

class ObjectClass extends slObject {

	private $_name;
	
	public $foo;
	
	public $sample;
	
	function getName() {
		return $this->_name;
	}	
	
	function setName($name) {
		$this->_name = $name;
	}
}





